package cn.coufran.springboot.starter.http;

import com.alibaba.fastjson2.JSON;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.http.HttpRequest;
import java.util.LinkedList;
import java.util.Queue;

public class BodyPublishers {
    private static final String BOUNDARY_DEFAULT = "-----------------BOUNDARY123456";

    public static HttpRequest.BodyPublisher ofJson(Object body) {
        String stringBody = JSON.toJSONString(body);
        return HttpRequest.BodyPublishers.ofString(stringBody);
    }

    public static HttpRequest.BodyPublisher ofMultipart(MultipartBody body) {
        return ofMultipart(body, BOUNDARY_DEFAULT);
    }

    public static HttpRequest.BodyPublisher ofMultipart(MultipartBody body, String boundary) {
        class MultipartBodyInputStream extends InputStream {
            private static final String BOUNDARY_FIX = "--";
            private static final String CRLF = "\r\n";

            private final Queue<InputStream> inputStreams = new LinkedList<>();
            private InputStream current;

            public MultipartBodyInputStream(MultipartBody body) {
                for (MultipartBody.MultipartBodyEntry entry : body.getEntries()) {
                    String name = entry.getName();
                    StringBuilder stringBuilder = new StringBuilder(CRLF)
                            .append(BOUNDARY_FIX).append(boundary).append(CRLF)
                            .append("Content-Disposition: form-data; name=\"").append(name).append("\"");
                    if (entry.isFile()) {
                        stringBuilder.append("; filename=\"pom.xml\"");
                    }
                    stringBuilder.append(CRLF);
                    MediaType mediaType = entry.getMediaType();
                    if (mediaType != null) {
                        stringBuilder.append("Content-Type: ").append(mediaType).append(CRLF);
                    }
                    stringBuilder.append(CRLF);
                    inputStreams.offer(new ByteArrayInputStream(stringBuilder.toString().getBytes()));

                    inputStreams.offer(entry.getInputStream());
                }
                StringBuffer stringBuilder = new StringBuffer(CRLF)
                        .append(BOUNDARY_FIX).append(boundary).append(BOUNDARY_FIX).append(CRLF);
                inputStreams.offer(new ByteArrayInputStream(stringBuilder.toString().getBytes()));
            }

            @Override
            public int read() throws IOException {
                int value;
                if (current == null || (value = current.read()) == -1) {
                    current = inputStreams.poll();
                    if (current == null) {
                        return -1;
                    }
                    value = current.read();
                }
                return value;
            }
        }

        return HttpRequest.BodyPublishers.ofInputStream(() -> new MultipartBodyInputStream(body));
    }
}